<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width,initial-scale=1.0"/>
    <title>MyBatis Pro</title>

    <!-- Google Fonts & 图标 -->
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;700&display=swap" rel="stylesheet"/>
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"/>

    <!-- Axios -->
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

    <!-- GSAP 动画库（保留，可继续用于 toast 等）-->
    <script src="https://cdn.jsdelivr.net/npm/gsap@3.12.2/dist/gsap.min.js"></script>

    <style>
        :root{
            --primary:#2563eb;
            --success:#16a34a;
            --bg:#f4f7fa;
            --radius:14px;
            --shadow:0 8px 32px rgba(0,0,0,.06);
            --transition:.6s ease;
        }
        *{box-sizing:border-box;margin:0;padding:0}
        body{
            font-family:'Inter',sans-serif;
            background:var(--bg);
            color:#1e293b;
            min-height:100vh;
            display:flex;
            align-items:flex-start;
            justify-content:center;
            padding:40px 20px;
        }
        .container{
            width:100%;
            max-width:1200px;
        }
        .title{
            font-size:2.8rem;
            font-weight:700;
            text-align:center;
            margin-bottom:50px;
            letter-spacing:-.5px;
            background:linear-gradient(135deg,var(--primary),#60a5fa);
            -webkit-background-clip:text;
            -webkit-text-fill-color:transparent;
        }

        /* ================= 滑动布局 ================= */
        .slide-wrapper{
            display:flex;
            gap:24px;
            align-items:flex-start;
        }
        .slide-wrapper .card{
            transition:transform var(--transition),flex var(--transition),opacity var(--transition);
        }

        /* 卡片默认样式 */
        .config-card{flex:1 1 100%}
        .tables-card {flex:0 0 0%;transform:translateX(100%);opacity:0}

        /* 收缩状态 */
        .config-card.collapsed{
            flex:0 0 48px;
            transform:translateX(-4px);
            overflow:hidden;
            cursor:pointer;
            padding:32px 8px;
            writing-mode:vertical-lr;
            justify-content:center;
            align-items:center;
            font-weight:600;
            color:var(--primary);
            background:#fff;
            box-shadow:var(--shadow);
            border-radius:var(--radius);
        }
        .config-card.collapsed .card-title,
        .config-card.collapsed .form-grid,
        .config-card.collapsed .btn-group{opacity:0;pointer-events:none}

        /* 表信息展开状态 */
        .tables-card.show{
            flex:1 1 70%;
            transform:translateX(0);
            opacity:1;
        }

        /* ================= 卡片通用样式 ================= */
        .card{
            background:#fff;
            border-radius:var(--radius);
            box-shadow:var(--shadow);
            padding:32px;
            position:relative;
        }
        .card-title{
            font-size:1.5rem;
            font-weight:600;
            margin-bottom:24px;
            display:flex;
            align-items:center;
            gap:8px;
        }
        .form-grid{
            display:grid;
            grid-template-columns:repeat(auto-fit,minmax(240px,1fr));
            gap:18px;
        }
        .form-group{
            display:flex;
            flex-direction:column;
            gap:6px;
        }
        .form-group.full-width{grid-column:1/-1}
        label{
            font-size:.875rem;
            font-weight:500;
            color:#475569;
        }
        input{
            padding:12px 14px;
            border:1px solid #cbd5e1;
            border-radius:10px;
            font-size:1rem;
            transition:border-color .25s,box-shadow .25s;
        }
        input:focus{
            border-color:var(--primary);
            box-shadow:0 0 0 3px rgba(37,99,235,.15);
            outline:none;
        }
        .btn-group{
            margin-top:28px;
            display:flex;
            gap:16px;
            flex-wrap:wrap;
        }
        .btn{
            flex:1 1 160px;
            padding:12px 0;
            border:none;
            border-radius:var(--radius);
            font-size:1rem;
            font-weight:600;
            cursor:pointer;
            color:#fff;
            display:flex;
            align-items:center;
            justify-content:center;
            gap:8px;
            transition:transform .2s,background .2s;
        }
        .btn.primary{background:var(--primary)}
        .btn.success{background:var(--success)}
        .btn:hover{transform:translateY(-2px)}
        .btn:active{transform:translateY(0)}

        /* 表格 */
        .table{
            width:100%;
            border-collapse:collapse;
            border-radius:var(--radius);
            overflow:hidden;
        }
        .table th,.table td{
            padding:14px 12px;
            font-size:.95rem;
            border-bottom:1px solid #e2e8f0;
        }
        .table th{background:#f1f5f9;font-weight:600}

        /* toast */
        .message{
            position:fixed;
            top:24px;right:24px;
            padding:16px 20px;
            border-radius:var(--radius);
            font-size:1rem;
            display:flex;
            align-items:center;
            gap:10px;
            animation:fadeIn .3s;
            z-index:9999;
        }
        .message.success{background:#ecfdf5;color:#065f46;border-left:4px solid var(--success)}
        .message.error{background:#fef2f2;color:#991b1b;border-left:4px solid #ef4444}
        @keyframes fadeIn{from{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}

        /* 加载动画 */
        .loader{
            width:20px;
            height:20px;
            border:3px solid rgba(255,255,255,.4);
            border-top-color:#fff;
            border-radius:50%;
            animation:spin .6s linear infinite;
        }
        @keyframes spin{to{transform:rotate(360deg)}}

        /* 响应式 */
        @media(max-width:520px){
            .title{font-size:2.2rem}
            .btn-group{flex-direction:column}
        }

        /* 让 slide-wrapper 始终在页面水平居中 */
        .slide-wrapper{
            display:flex;
            gap:24px;
            align-items:flex-start;
            justify-content:center;   /* 关键：水平居中 */
        }
    </style>
</head>
<body>

<div class="container">
    <h1 class="title">MyBatis Pro</h1>

    <!-- 滑动容器 -->
    <div class="slide-wrapper">

        <!-- 数据库配置卡 -->
        <div class="card config-card">
            <h2 class="card-title">
                <span class="material-icons">storage</span>数据库配置
            </h2>
            <div class="form-grid">
                <div class="form-group">
                    <label>数据库地址 (Host)</label>
                    <input id="host" placeholder="localhost"/>
                </div>
                <div class="form-group">
                    <label>端口</label>
                    <input id="port" placeholder="3306"/>
                </div>
                <div class="form-group">
                    <label>数据库名</label>
                    <input id="database" placeholder="database"/>
                </div>
                <div class="form-group">
                    <label>字符集</label>
                    <input id="charset" placeholder="utf8"/>
                </div>
                <div class="form-group">
                    <label>用户名</label>
                    <input id="username" placeholder="root"/>
                </div>
                <div class="form-group">
                    <label>密码</label>
                    <input id="password" type="password" placeholder="******"/>
                </div>
                <div class="form-group full-width">
                    <label>输出路径</label>
                    <input id="outputPath" placeholder="C:/Users/LENOVO/Desktop/java-demo"/>
                </div>
            </div>

            <div class="btn-group">
                <button class="btn primary" id="btnGetTables">
                    <span class="material-icons">table_view</span>
                    <span>获取表信息</span>
                </button>
                <button class="btn success" id="btnGenCode">
                    <span class="material-icons">auto_fix_high</span>
                    <span>生成代码</span>
                </button>
            </div>
        </div>

        <!-- 表信息卡 -->
        <div class="card tables-card" id="tablesCard">
            <h2 class="card-title">
                <span class="material-icons">view_list</span>表信息
            </h2>
            <table class="table" id="tablesTable">
                <thead>
                <tr><th>表名</th><th>注释</th></tr>
                </thead>
                <tbody id="tablesBody"></tbody>
            </table>
        </div>

    </div><!-- slide-wrapper end -->

    <!-- 全局 toast 容器 -->
    <div id="message" style="display:none;"></div>
</div>

<script>
    /* 工具函数 */
    const $ = id => document.getElementById(id);
    const getVal = (id,def) => $(id).value.trim() || def;

    const buildJdbcUrl = () => {
        const host = getVal('host','localhost');
        const port = getVal('port','3306');
        const db   = getVal('database','database');
        const cs   = getVal('charset','utf8');
        return `jdbc:mysql://${host}:${port}/${db}?useUnicode=true&characterEncoding=${cs}`;
    };

    /* Toast */
    const toast = (text,type='success') => {
        const box = $('message');
        box.className = `message ${type}`;
        box.innerHTML = `<span class="material-icons">${type==='success'?'check_circle':'error'}</span>${text}`;
        box.style.display = 'flex';
        gsap.fromTo(box,{y:-10,opacity:0},{y:0,opacity:1,duration:.3});
        setTimeout(()=> gsap.to(box,{y:-10,opacity:0,duration:.3,onComplete:()=>box.style.display='none'}),3000);
    };

    const showLoader = (btn,show=true) => {
        const icon = btn.querySelector('.material-icons');
        const txt  = btn.querySelector('span:last-child');
        if(show){
            icon.style.display='none';
            btn.insertAdjacentHTML('afterbegin','<div class="loader"></div>');
            btn.disabled = true;
        }else{
            btn.querySelector('.loader')?.remove();
            icon.style.display='inline';
            btn.disabled = false;
        }
    };

    /* 事件：获取表信息 */
    $('btnGetTables').addEventListener('click',async ()=>{
        const btn = $('btnGetTables');
        showLoader(btn,true);
        try{
            const res = await axios.post('/codegen/tables',{
                url: buildJdbcUrl(),
                username: getVal('username','root'),
                password: getVal('password','123456')
            });
            const tbody = $('tablesBody'); tbody.innerHTML='';
            res.data.forEach(t=>{
                const tr=document.createElement('tr');
                tr.innerHTML=`<td>${t.tableName}</td><td>${t.comment}</td>`;
                tbody.appendChild(tr);
            });

            /* 触发动画 */
            document.querySelector('.config-card').classList.add('collapsed');
            document.querySelector('.tables-card').classList.add('show');
            toast('获取成功！');
        }catch(e){
            toast('获取失败：'+e,'error');
        }finally{ showLoader(btn,false); }
    });

    /* 事件：生成代码 */
    $('btnGenCode').addEventListener('click',async ()=>{
        const btn = $('btnGenCode');
        showLoader(btn,true);
        try{
            const outPath = encodeURIComponent(getVal('outputPath','C:/Users/LENOVO/Desktop/java-demo'));
            const res = await axios.post(`/codegen/generate?outputPath=${outPath}`,{
                url: buildJdbcUrl(),
                username: getVal('username','root'),
                password: getVal('password','123456')
            });
            toast(res.data);
        }catch(e){
            toast('生成失败：'+e,'error');
        }finally{ showLoader(btn,false); }
    });

    /* 点击左侧抽屉条还原布局 */
    document.querySelector('.config-card').addEventListener('click',function(){
        if(this.classList.contains('collapsed')){
            this.classList.remove('collapsed');
            document.querySelector('.tables-card').classList.remove('show');
        }
    });
</script>

</body>
</html>